package com.forecasting.statistic;

import static com.forecasting.utility.Utility.formatDecimal;

import com.forecasting.interfaces.Distribution;
import com.forecasting.model.PartNumber;
import com.forecasting.utility.NormalDistributionExtractor;

import java.io.Serializable;
import java.util.*;

public class NormalDistribution implements Distribution,Serializable{

	private PartNumber pn = null;
	
	//used to see if rop has changed
	
	private double lambda = 0;
	private double serviceLevel = 0;
	private double Z =  0;
	
	private NormalDistributionExtractor nde = new NormalDistributionExtractor();
		
	public NormalDistribution(PartNumber partnumber){
		this.pn = partnumber;
		
		this.lambda = pn.getForecast() * pn.getLeadtime();
		this.serviceLevel = calcOriginalServicelevel();
	}

	private double calcOriginalServicelevel(){
		/* Exposant = Math.pow(x,y)*/
		double sl = 0;
		double ss1 = pn.getRop() - lambda;
		double Z = (ss1)/(Math.sqrt(pn.getLeadtime()) * pn.getStandardDeviation());
		this.Z = Z;
		//test extreme limits 0.00 and 100.00
		if( Z < -3.719016485 ){
			sl = 0.0;
		}else if ( Z > 3.719016486){
			sl = 1.000;
		}else{
			//will return the SL less that the key in between
			NavigableMap<Double,Double> slMap = nde.getServiceLevelMap();
			double temp = slMap.get(slMap.floorEntry(Z).getKey());
			sl = temp;
		}
		
		return sl;	
	}
	public double changeRop(int reorderPoint){
		this.pn.setRop(reorderPoint);
		this.serviceLevel = calcOriginalServicelevel();
		return this.serviceLevel;
	}
	@Override
	public int getCalculatedROP(double serviceLevel) {
		return calcRop(serviceLevel);
	}	
	private int calcRop(double sl){
		/* Exposant = Math.pow(x,y)*/
		double Z = nde.getZStatMap().get(sl);
		int ropSL = 0;
		
		double SS = Z * Math.sqrt(pn.getLeadtime()) * pn.getStandardDeviation();
		ropSL = (int)((pn.getForecast() * pn.getLeadtime()) + SS);
		
		return ropSL;
	}	
	public void recalculateServiveLevel(){
		this.serviceLevel = calcOriginalServicelevel();
	}
	
	public double getServiceLevel() {
		return this.serviceLevel;
	}
	public String toString(){
		String resStr = pn.toString() + "\n";
		resStr = resStr + "Forecast: " + pn.getForecast()+ " Leadtime: " + pn.getLeadtime() + 
		"\nROP: " + pn.getRop() + " Service level: " + formatDecimal(getServiceLevel(),4) * 100 +"% " +
		"Z: " + Z +"\n";
		//resStr = resStr 
		return resStr;
	}

}
